﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Lizk.SimpleHUD;
using SdlDotNet.Graphics;
using SharpMedia.MDX;
using System.IO;
using System.Drawing;
using SdlDotNet.Graphics.Primitives;

namespace SDLHUDEngine
{
    public class Renderer : HUDRenderer
    {
        public string FontRootDir { get; set; }
        public string ImageRoot { get; set; }
        public TimeSpan GarbageCollectionInterval { get; set; }

        private Dictionary<string, ImageContainer> images = new Dictionary<string, ImageContainer>();
        private Dictionary<HUDLabel, StringCache> stringCache = new Dictionary<HUDLabel, StringCache>();
        private Dictionary<string, List<ImageContainer>> fonts = new Dictionary<string, List<ImageContainer>>();
        //private Dictionary<string, XNAVideo> videos = new Dictionary<string, XNAVideo>();

        public string ImagePath(string image)
        {
            if (!File.Exists(image))
            {
                string test = Path.Combine(ImageRoot, image);
                if (File.Exists(test))
                    return test;
            }
            return image;

        }

        ~Renderer()
        {
            Dispose();
        }

        #region HUDRenderer Members

        public bool ImageLoaded(HUDImage image)
        {
            if (string.IsNullOrEmpty(image.File))
                return false;

            if (images.ContainsKey(Path.GetFullPath(ImagePath(image.File)).ToLower()))
            {
                if (image.ImageSize == RectangleS.Empty && images[Path.GetFullPath(ImagePath(image.File)).ToLower()].Image.IsLoaded)
                {
                    image.ImageSize = new RectangleS(images[Path.GetFullPath(ImagePath(image.File)).ToLower()].Image.SourceRectangle.X, images[Path.GetFullPath(ImagePath(image.File)).ToLower()].Image.SourceRectangle.Y, images[Path.GetFullPath(ImagePath(image.File)).ToLower()].Image.SourceRectangle.Width, images[Path.GetFullPath(ImagePath(image.File)).ToLower()].Image.SourceRectangle.Height);
                    if (!image.IsFading && image.FadeOnLoad)
                    {
                        byte alpha = (byte)image.Alpha;
                        image.Alpha = 1;
                        image.Fade(alpha, 6f);
                    }
                }
                return true;
            }
            else
                return false;
        }

        public void LoadImage(HUDImage image)
        {
            if (string.IsNullOrEmpty(image.File))
                return;
            if (!File.Exists(ImagePath(image.File)))
                return;

            SDLImage img = SDLImage.FromFile(Path.GetFullPath(ImagePath(image.File)).ToLower(), null, System.Drawing.Size.Empty);
            images.Add(Path.GetFullPath(ImagePath(image.File)).ToLower(), new ImageContainer(img));

        }

        public void UnloadImage(HUDImage image)
        {
            if (string.IsNullOrEmpty(image.File) || string.IsNullOrEmpty(ImagePath(image.File)))
                return;
            if (images.ContainsKey(Path.GetFullPath(ImagePath(image.File)).ToLower()))
            {
                if (images[Path.GetFullPath(ImagePath(image.File)).ToLower()] != null)
                    images[Path.GetFullPath(ImagePath(image.File)).ToLower()].Image.Dispose();
                images.Remove(Path.GetFullPath(ImagePath(image.File)).ToLower());
            }
        }

        public void PaintImage(RectangleS bounds, RectangleS source, byte alpha, HUDImage image)
        {
            string imageKey = Path.GetFullPath(ImagePath(image.File)).ToLower();

            if (images.ContainsKey(imageKey) && images[imageKey].Image.IsLoaded)
            {

                if (image.EffectTag == null)
                {
                    SDLImage mimage = images[imageKey].Image;

                    Rectangle sourceRect = new Rectangle((int)source.X + mimage.SourceRectangle.X, (int)source.Y + mimage.SourceRectangle.Y, (int)Math.Ceiling(source.Width), (int)Math.Ceiling(source.Height));
                    if (sourceRect == Rectangle.Empty)
                        return;

                    //mimage.Texture.Alpha = alpha;

                    


                    mimage.Texture.Alpha = alpha;

                    if (bounds.Width != mimage.Texture.Width || bounds.Height != mimage.Texture.Height)
                    {

                        Surface sf = mimage.Texture.Surface.CreateScaledSurface(bounds.Width / (float)mimage.Texture.Width, bounds.Height / (float)mimage.Texture.Height, true);
                        Video.Screen.Blit(sf, new Rectangle((int)bounds.X, (int)bounds.Y, (int)bounds.Width, (int)bounds.Height), sourceRect);
                        sf.Dispose();
                    }
                    else
                    {
                        Video.Screen.Blit(mimage.Texture.Surface, new Rectangle((int)bounds.X, (int)bounds.Y, (int)bounds.Width, (int)bounds.Height), sourceRect);
                    }
                    //mainDrawSprite.Draw(mimage.Texture, , sourceRect, new Color(image.Color.R, image.Color.G, image.Color.B, alpha));
                }
               
            }
        }

        public bool VideoLoaded(HUDVideo2 video)
        {
            return false;
        }

        public void LoadVideo(HUDVideo2 video)
        {
        }

        public void UnloadVideo(HUDVideo2 video)
        {
        }

        public void PaintVideo(RectangleS bounds, RectangleS source, byte alpha, HUDVideo2 video)
        {
        }

        public bool HasFont(HUDFont hudFont)
        {
            return false;
        }

        public void LoadFont(HUDFont hudFont)
        {
        }

        public void UnloadFont(HUDFont hudFont)
        {
        }

        public void PaintText(RectangleS paintArea, RectangleS rectangleS, int a, HUDLabel font, int page)
        {
        }

        public void EnterContainer(RectangleS activeArea)
        {
        }

        public void LeaveContainer(RectangleS activeArea)
        {
        }

        public SizeS GetCanvasSize()
        {
            return new SizeS(1280, 720);
        }

        public void Reset()
        {
        }

        public void Initialize()
        {
        }

        public void BeginDraw()
        {
            Video.Screen.Fill(Color.Black);
        }

        public void EndDraw()
        {
            Video.Update();
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            foreach (ImageContainer image in images.Values)
            {
                image.Image.Dispose();
            }
            images.Clear();

            foreach (StringCache f in stringCache.Values)
            {
                if (f.image.Texture != null)
                    f.image.Texture.Dispose();
            }
            stringCache.Clear();

            foreach (KeyValuePair<string, List<ImageContainer>> kvp in fonts)
            {
                foreach (ImageContainer i in kvp.Value)
                {
                    i.Image.Dispose();
                }
            }
            fonts.Clear();
        }

        #endregion


        private class ImageContainer
        {
            private SDLImage image;
            private DateTime lastUsed = DateTime.Now;
            public DateTime LastUsed
            {
                get { return lastUsed; }
            }
            public SDLImage Image
            {
                get
                {
                    lastUsed = DateTime.Now;
                    return image;
                }
                set { image = value; }
            }
            public ImageContainer(SDLImage image)
            {
                this.image = image;
            }
        }

        private class StringCache
        {
            public string font;
            public Lizk.SimpleHUD.Alignment alignment;
            public string text;
            public SizeS size;
            public TextureContainer image;
            public StringCache(string font, Lizk.SimpleHUD.Alignment alignment, string text, SizeS size)
            {
                this.font = font;
                this.alignment = alignment;
                this.text = text;
                this.size = size;
                this.image = null;
            }

            public static StringCache FromLabel(HUDLabel label)
            {
                return new StringCache(label.Font, label.Alignment, label.Text, label.Size);
            }

            public override bool Equals(object obj)
            {
                if (obj is StringCache)
                {
                    StringCache fc = (StringCache)obj;

                    return fc.font == font && fc.alignment == alignment && fc.text == text && size == fc.size;
                }
                else
                    return base.Equals(obj);
            }
            public override int GetHashCode()
            {
                return base.GetHashCode();
            }
        }

        private class TextureContainer
        {
            private Surface texture;
            private DateTime lastUsed = DateTime.Now;
            private RectangleS source;

            public RectangleS Source
            {
                get { return source; }
                set { source = value; }
            }

            public DateTime LastUsed
            {
                get { return lastUsed; }
            }
            public Surface Texture
            {
                get
                {
                    lastUsed = DateTime.Now;
                    return texture;
                }
                set { texture = value; }
            }

            public TextureContainer(Surface t)
            {
                this.texture = t;
            }
        }
    
    }



}
